/*
 * Copyright (C) 2010 Graham Allan
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.strath.cis.grallan.findbugs.adaptiveranking.gui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.Icon;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;

import edu.strath.cis.grallan.findbugs.adaptiveranking.IBugRankMap;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.gui2.BugLeafNode;
import edu.umd.cs.findbugs.gui2.BugRenderer;

/**
 * @author Graham Allan (grallan@cis.strath.ac.uk)
 */
public class RankedBugRenderer extends BugRenderer {

	private BugInstance currentBug;
	private final IBugRankMap bugRankMap;

	public RankedBugRenderer(IBugRankMap bugRankMap) {
		this.bugRankMap = bugRankMap;
	}

	@Override
	public Component getTreeCellRendererComponent(JTree tree, Object node, boolean selected, boolean expanded,
			boolean leaf, int row, boolean hasFocus) {

		setCurrentBugFromNode(node);

		return super.getTreeCellRendererComponent(tree, node, selected, expanded, leaf, row, hasFocus);
	}

	/**
	 * This must be called before the calling the super implementation of
	 * getTreeCellRendererComponent, as getLeafIcon is called during the course of the method, and
	 * bug must be set by then.
	 * 
	 * @see DefaultTreeCellRenderer#getTreeCellRendererComponent()
	 */
	private void setCurrentBugFromNode(Object node) {
		if ((node instanceof BugLeafNode)) {
			currentBug = ((BugLeafNode) node).getBug();
		}
	}

	@Override
	public Icon getLeafIcon() {
		double rank = bugRankMap.relativeRankFor(currentBug);
		double defaultRank = bugRankMap.defaultRelativeRank();
		return new RankedAlertIcon(rank, defaultRank);
	}

	private static class RankedAlertIcon implements Icon {

		private final double rank;
		private final double defaultRank;
		private static final int arcWidth = 5;
		private static final int arcHeight = 3;

		/**
		 * Creates an icon representing the rank of the current bug. If the current bug is null,
		 * creates a neutral representation.
		 * 
		 * @param defaultRank
		 * 
		 * @param currentBug
		 * @param bugRankMap
		 */
		public RankedAlertIcon(double rank, double defaultRank) {
			this.rank = rank;
			this.defaultRank = defaultRank;
		}

		public int getIconHeight() {
			return 10;
		}

		public int getIconWidth() {
			return 40;
		}

		public void paintIcon(Component c, Graphics g, int x, int y) {
			Graphics2D g2d = (Graphics2D) g;

			setColorBasedOnRank(g2d);

			int defaultX = (int) (defaultRank * getIconWidth());

			// draw rectangle inside
			if (rank < defaultRank) {
				paintRankLessThanDefault(y, defaultX, g2d);
			} else if (rank >= defaultRank) {
				paintRankGreaterThanDefault(y, defaultX, g2d);
			}

			// draw outer line
			g2d.setColor(Color.BLACK);
			g2d.drawRoundRect(x, y, getIconWidth(), getIconHeight(), arcWidth, arcHeight);

			// draw medium line
			g2d.drawLine(x + defaultX, y, x + defaultX, y + getIconHeight());

		}

		private void setColorBasedOnRank(Graphics2D g2d) {
			float red = (float) (1 - rank);
			float green = (float) rank;
			Color color = new Color(red, green, 0.0f);
			g2d.setColor(color);
		}

		private void paintRankGreaterThanDefault(int y, int defaultX, Graphics2D g2d) {
			double dWidth = ((rank * getIconWidth()) - (defaultRank * getIconWidth()));
			int width = (int) Math.round(dWidth);
			g2d.fillRoundRect(defaultX, y, width, getIconHeight(), arcWidth, arcHeight);
		}

		private void paintRankLessThanDefault(int y, int defaultX, Graphics2D g2d) {
			double dWidth = ((defaultRank * getIconWidth()) - (rank * getIconWidth()));
			int width = (int) Math.round(dWidth);
			g2d.fillRoundRect(defaultX - width, y, width, getIconHeight(), arcWidth, arcHeight);
		}

	}

}
